function PDRenderStatus(){
    this.domDoc = null;
    this.canvas = null;
    this.m_curObj = null; //currently rendering object
    this.m_curObjList = null;//maybe a page's object list or a form's
    this.m_lastClip = null; // last clipping path points. a PDClipPathState instance.
    this.m_txtClipLayer = null; // a canvas for text clipping.
    this.viewScale = 1;
    this.m_mode = 0; //0:IE, 1 : web-kit, 2:firefox,
    this.m_Transparency = 0;
    
    this.m_stopObj = null;
    this.m_nLevle = 0;
    this.m_renderContext = null;

 
    this.Init = function (level, renderContext, cnvs, stopObj, viewScale, transparency) {
        this.m_nLevel = level;
        this.m_renderContext = renderContext;
        this.canvas = cnvs;
        this.m_stopObj = stopObj;
        this.m_Transparency = transparency;
        this.viewScale = viewScale;
    };

};


PDRenderStatus.prototype.RenderObjList = function (objs, mtObj2Device, mode) {
    if (objs == null) return;
    if (this.m_nLevle > 32) return;
    var prev = this.m_curObjList;
    this.m_curObjList = objs;
    //this.m_Transparency = this.m_curObjList.m_Transparency;
    for (var i = 0, objCount = objs.objectArr.length; i < objCount; i++) {
        var obj = objs.objectArr[i];
        if (obj == this.m_stopObj) break;
        this.RenderSingleObj(obj, mtObj2Device, mode);
    }
    this.m_curObjList = prev;
};


PDRenderStatus.prototype.ProcessClipPath = function (obj, mtObj2Device, mode) {
    var clipPathState = this.GetClipPathStateByID(obj.nClipPathStateID);
    if (clipPathState == undefined || clipPathState == null) return;
    var generalState = this.GetGenStateByID(obj.nGenStateID);

    var clipPathData = clipPathState.clipPath;
    //set path clipping
    for (var i = 0; i < clipPathData.length; i++) {
        var path = clipPathData[i];
        this.SetSingleClip(path, mtObj2Device);
    }

    //prepare text cliping layer
    //var bbox = obj.GetBBox(mtObj2Device)
    this.CreateTextClipLayer(clipPathState, mtObj2Device);
    this.m_lastClip = clipPathState;
};

PDRenderStatus.prototype.RenderSingleObj = function (obj, mtObj2Device, mode) {
    if (this.m_Level > 32) return;

    if (obj instanceof FormObj) {
        if (obj.form.CountObj() < 1) return;
    }

    this.m_curObj = obj;
    // process single now. First clipping
    var ctx = this.canvas.getContext("2d");
    ctx.save();
    this.ProcessClipPath(obj, mtObj2Device, mode);
    //then process transparency
    if (this.ProcessTransparency(obj, mtObj2Device, mode)) return;

    this.ProcessSingleObjNoClip(obj, mtObj2Device, mode);

    //now, do text clip.
    if (this.m_txtClipLayer != null) {
        if (obj instanceof PathObj || obj instanceof ImgObj)
            obj.CalcBBox();
        var rc = mtObj2Device.TransFormRect(obj.position[0], obj.position[1], obj.position[2], obj.position[3]);
        this.DoTextClipping(this.canvas, rc);
        this.m_txtClipLayer = null;
    }
    ctx.restore();
};
PDRenderStatus.prototype.DoTextClipping = function (cnvs, rcClip) {

    if (this.m_txtClipLayer == null) return;

    //first, we store the page image;
    var ctx = cnvs.getContext("2d");
    var imgPage = ctx.getImageData(0, 0, this.canvas.width, this.canvas.height);

    //then do text clipping effects
    var maskCtx = this.m_txtClipLayer.getContext("2d");
    maskCtx.save();
    maskCtx.setTransform(1, 0, 0, 1, 0, 0);
    maskCtx.globalCompositeOperation = 'source-in';
    maskCtx.drawImage(this.canvas, 0, 0);
    maskCtx.restore();

    //  var newCnv = document.getElementById("myCanvas2");

    //var newCtx = newCnv.getContext("2d");
    var img = ctx.getImageData(0, 0, this.canvas.width, this.canvas.height);

    //newCtx.putImageData(img, 0, 0);
    var rcObj = rcClip; // this.matrix.TransFormRect(this.m_curObj.position[0], this.m_curObj.position[1], this.m_curObj.position[2], this.m_curObj.position[3]);
    var left = Math.round(rcObj[0]);
    var top = Math.round(rcObj[1]);
    //now we just draw text image directly, because the clipping region have been set.
    var w = Math.round(rcObj[2] - rcObj[0]);
    var h = Math.round(rcObj[3] - rcObj[1]);
    var imgText = maskCtx.getImageData(left, top, w, h);
    ctx.save();
    ctx.setTransform(1, 0, 0, 1, 0, 0);
    ctx.putImageData(imgText, left, top);
    ctx.restore();
};

PDRenderStatus.prototype.NormalizeRect = function (rect) {
    if (rect[0] > rect[2]) {
        var temp = rect[2];
        rect[2] = rect[0];
        rect[0] = temp;
    }
    if (rect[1] > rect[3]) {
        var temp = rect[3];
        rect[3] = rect[1];
        rect[1] = temp;
    }
    return rect;
};

PDRenderStatus.prototype.ProcessTransparency = function (obj, mtObj2Dev, mode) {
    if (obj == undefined || obj == null) return false;
    //return false;

    var genState = this.GetGenStateByID(obj.nGenStateID);
    var blend_type = (genState != null) ? genState.blendType : 0;
    if (blend_type == -1) return true; // not doing anything

    var softMask = (genState != null) ? genState.m_softMask : null;
    if (softMask) {
        if (obj instanceof ImgObj) {
            // Wait: According to PDF Reference, already soft-masked images can't use the soft mask
            // in graphic states any more. 
            if (obj.m_bUsedSoftMask)
                softMask = null;
        }
    }

    var group_alpha = 1.0;
    var Transparency = this.m_Transparency;
    var bGroupTransparent = false;
    var bForm = (obj instanceof FormObj);
    if (bForm) {
        if (genState)
            group_alpha = genState.fillAlpha;
        Transparency = obj.form.pdPageObjects.m_Transparency;
        bGroupTransparent = Transparency & 0x0200 ? true : false;



    }

    var clipPathState = this.GetClipPathStateByID(obj.nClipPathStateID);
    var bTextClip = false;
    if (clipPathState != null) {
        var nText = clipPathState.CountTextClipObjs();
        if (nText > 0) bTextClip = true;
    }
    //var bTextClip = this.m_txtClipLayer != null;
    if (softMask == null && group_alpha == 1.0 && blend_type == 0 /*&& !bTextClip*/ && !bGroupTransparent)
        return false; // no need for special process

    var isolated = Transparency & 0x0200;
    var rect = obj.GetBBox(mtObj2Dev);
    if (rect[0] < 0) rect[0] = 0;
    if (rect[1] < 0) rect[1] = 0;
    if (rect[2] < 0) rect[2] = 0;
    if (rect[3] < 0) rect[3] = 0;
    if (rect[0] > this.canvas.width) rect[0] = this.canvas.width;
    if (rect[1] > this.canvas.height) rect[1] = this.canvas.height;
    if (rect[2] > this.canvas.width) rect[2] = this.canvas.width;
    if (rect[3] > this.canvas.height) rect[3] = this.canvas.height;
    for (var i = 0; i < 4; i++) {
        rect[i] = Math.floor(rect[i]);
    }

    PDRenderStatus.prototype.NormalizeRect(rect);
    var width = Math.abs(rect[2] - rect[0]);
    var height = Math.abs(rect[3] - rect[1]);
    if (width <= 0 || height <= 0) return true;

    if (bForm) {
        //record this formobj
        if (!this.m_renderContext.BelongToCurRenderingForm(obj)) {
            this.m_renderContext.SetCurRenderFormRecord(obj);
            this.m_renderContext.SaveBackground();
        }
    }


    var bitmap_device = document.createElement("canvas"); //document.getElementById('myCanvas'); //
    bitmap_device.width = this.canvas.width;
    bitmap_device.height = this.canvas.height;

    //save backdrop;
    //render object on a layer;
    var status = new PDRenderStatus();
    //level, renderContext, cnvs, stopObj, transparency
    status.Init(this.m_Level + 1, this.m_renderContext, bitmap_device, this.m_stopObj, this.m_Transparency);
    status.m_curObjList = this.m_curObjList;
    //render the object layer
    status.ProcessSingleObjNoClip(obj, mtObj2Dev, mode);


    var bmpCtx = bitmap_device.getContext("2d");
    var bitmap = bmpCtx.getImageData(rect[0], rect[1], width, height);
    //do soft mask
    if (softMask != null) {
        var maskData = softMask.GetMaskData(this.canvas.width, this.canvas.height, rect, mtObj2Dev);
        status.MultiplyMask(bitmap, rect[0], rect[1], maskData);
        if (null != this.m_renderContext.m_curRenderFormRecord)
            this.m_renderContext.m_curRenderFormRecord.m_UsedAlphaRects.push(rect);
    }
    //now, do text clip.
    /*
    if (this.m_txtClipLayer != null) {
    if (obj instanceof PathObj || obj instanceof ImgObj)
    obj.CalcBBox();
    var rc = mtObj2Dev.TransFormRect(obj.position[0], obj.position[1], obj.position[2], obj.position[3]);
    this.DoTextClipping(bitmap_device, rc);
    this.m_txtClipLayer = null;
    }
    */
    /*
    var bmpCtx = bitmap_device.getContext("2d");
    var imgData = bmpCtx.getImageData(rect[0], rect[1], width, height);
    var tCnvs = document.getElementById('myCanvas'); //document.createElement("canvas"); //  
    tCnvs.width = width;
    tCnvs.height = height;
    var tCtx = tCnvs.getContext("2d");
    // tCtx.putImageData(imgData, 0, 0);
    //tCtx.putImageData(bitmap, 0, 0);

    var c = document.createElement("canvas"); // document.getElementById('myCanvas'); //
    c.width = width;
    c.height = height;
    var newCtx = c.getContext("2d");
    //newCtx.drawImage(tCnvs, 0, 0, width, height);
    newCtx.putImageData(bitmap, 0, 0);
    tCtx.drawImage(c, 0, 0, width, height);
    */

    // If this object is in a group, then this group might be transparent itself
    var bUseAlpha = false;
    if (Transparency & 0x0100 && group_alpha != 1.0) {
        status.MultiplyAlpha(bitmap, rect[0], rect[1], width, height, (group_alpha * 255));
        bUseAlpha = true;
        if (null != this.m_renderContext.m_curRenderFormRecord)
            this.m_renderContext.m_curRenderFormRecord.m_UsedAlphaRects.push(rect);
    }

    Transparency = this.m_Transparency;

    if (obj instanceof FormObj)
        Transparency |= 0x0100;

    var bIsolated = Transparency & 0x0200;
    var bGroup = Transparency & 0x0100;

    var bgBmp = this.m_renderContext.m_bitmap;
    var bBackgroundRectUsedAlpha = false;
    if (null != this.m_renderContext.m_curRenderFormRecord)
        bBackgroundRectUsedAlpha = this.m_renderContext.m_curRenderFormRecord.RectIsUsedAlpha(rect);

    if (this.m_renderContext.m_curRenderFormRecord == null) {
        //now we composite the bitmap and output to dest canvas
        if (blend_type == 0 || bIsolated || !bGroup) {
            //  this.BitBlt(this.canvas, bitmap, rect[0], rect[1], width, height);

            var ctx = this.canvas.getContext("2d");
            var backdrop = ctx.getImageData(rect[0], rect[1], width, height);
            if ((softMask != null) || bUseAlpha) {
                BmpCompositer.prototype.CompositeRgba2Rgb_NoBlend(backdrop, 0, 0, width, height, bitmap, 0, 0, null);
            } else if (blend_type) {
                BmpCompositer.prototype.CompositeRgba2Rgb_Blend(backdrop, 0, 0, width, height, bitmap, 0, 0, blend_type, null);
            } else {
                BmpCompositer.prototype.CompositeRgba2Rgb_NoBlend(backdrop, 0, 0, width, height, bitmap, 0, 0, null);
            }
           
            //this.BitBlt(this.canvas, backdrop, rect[0], rect[1], width, height);
             ctx.putImageData(backdrop, rect[0], rect[1]);

            return true;
        }
        if (!bIsolated && bGroup) {
            //we should use backdrop, implement in feauture;
            //if has backdrop:
            //Do backdrop process here

            //todo

            //if no backdrop, composite it directly
            var ctx = this.canvas.getContext("2d");
            var backdrop = ctx.getImageData(rect[0], rect[1], width, height);
            if ((softMask != null) || bUseAlpha) {
                BmpCompositer.prototype.CompositeRgba2Rgb_NoBlend(backdrop, 0, 0, width, height, bitmap, 0, 0, null);
            } else if (blend_type) {
                BmpCompositer.prototype.CompositeRgba2Rgb_Blend(backdrop, 0, 0, width, height, bitmap, 0, 0, blend_type, null);
            } else {
                BmpCompositer.prototype.CompositeRgba2Rgb_NoBlend(backdrop, 0, 0, width, height, bitmap, 0, 0, null);
            }

            //this.BitBlt(this.canvas, backdrop, rect[0], rect[1], width, height);
            ctx.putImageData(backdrop, rect[0], rect[1]);
            return true;
        }
        return true;
    } else if (this.m_renderContext.BelongToCurRenderingForm(obj)) {
        //just composite in memory
        if (bBackgroundRectUsedAlpha) {
            BmpCompositer.prototype.CompositeRgba2Rgba(bgBmp, bitmap, rect[0], rect[1], width, height, 0, 0, blend_type, null);
            return true;
        }
        if (blend_type) {
            BmpCompositer.prototype.CompositeRgba2Rgb_Blend(bgBmp, rect[0], rect[1], width, height, bitmap, 0, 0, blend_type, null);
            return true;
        }

        BmpCompositer.prototype.CompositeRgba2Rgb_NoBlend(bgBmp, rect[0], rect[1], width, height, bitmap, 0, 0, null);
        return true;
    } else if (obj == this.m_renderContext.m_curRenderFormRecord.formObj) {
        //composit and output
        if (bBackgroundRectUsedAlpha) {
            BmpCompositer.prototype.CompositeRgba2Rgba(bgBmp, bitmap, rect[0], rect[1], width, height, 0, 0, blend_type, null);
            // return true;
        } else if (blend_type) {
            BmpCompositer.prototype.CompositeRgba2Rgb_Blend(bgBmp, rect[0], rect[1], width, height, bitmap, 0, 0, blend_type, null);
            // return true;
        } else {
            BmpCompositer.prototype.CompositeRgba2Rgb_NoBlend(bgBmp, rect[0], rect[1], width, height, bitmap, 0, 0, null);
        }


        var ctx = this.m_renderContext.canvas.getContext("2d");
        ctx.putImageData(bgBmp, 0, 0);
        this.m_renderContext.FreeBackground();
        this.m_renderContext.m_curRenderFormRecord = null;
        return true;
    }
    return false;

};
PDRenderStatus.prototype.MultiplyMask = function (bitmap, left, top, maskData) {
    for (var i = 0; i < bitmap.data.length; i += 4) {
        var old = bitmap.data[i + 3];
        var msk = maskData.data[i / 4];

        bitmap.data[i + 3] = (old * msk) / 255;
    }
};
PDRenderStatus.prototype.MultiplyAlpha = function (bitmap, left, top, width, height, alpha) {
   // var ctx = cnvs.getContext("2d");
   // var imgData=ctx.getImageData(left,top,width,height);
    for (var i = 0; i < bitmap.data.length; i += 4)
    {
        var old = bitmap.data[i + 3];
        bitmap.data[i + 3] = (old * alpha) / 255;
     }
   // ctx.putImageData(imgData,left,top);
};
PDRenderStatus.prototype.BitBlt = function (destCnvs, srcBmp, left, top, width, height) {
    var ctx = destCnvs.getContext("2d");
 //   ctx.putImageData(srcBmp, left, top);
 //   return;
    if (this.m_renderContext.globalUseAlphaWhenBitblt) {
        var tempCnvs = document.createElement("canvas"); //
        tempCnvs.width = width;
        tempCnvs.height = height;
        var tmpCtx = tempCnvs.getContext("2d");
        tmpCtx.putImageData(srcBmp, 0, 0);
        ctx.drawImage(tempCnvs, left, top);

    } else {
        ctx.putImageData(srcBmp, left, top);
    }

};

PDRenderStatus.prototype.CompositeBitmap = function (bitmap, left, top, width, height, mask_rgba, bitmap_alpha, blend_mode, transparency, bOutput) {
    var bIsolated = transparency & 0x0200;
    var bGroup = transparency & 0x0100;

    if (blend_type == 0) {
        var ctx = this.canvas.getContext("2d");
        var backdrop = ctx.getImageData(rect[0], rect[1], width, height);
        if ((softMask != null) || bUseAlpha) {
            BmpCompositer.prototype.CompositeRgba2Rgb_NoBlend(backdrop, 0, 0, width, height, bitmap, 0, 0, null);
        } else if (blend_type) {
            BmpCompositer.prototype.CompositeRgba2Rgb_Blend(backdrop, 0, 0, width, height, bitmap, 0, 0, blend_type, null);
        } else {
            BmpCompositer.prototype.CompositeRgba2Rgb_NoBlend(backdrop, 0, 0, width, height, bitmap, 0, 0, null);
        }

        //this.BitBlt(this.canvas, backdrop, rect[0], rect[1], width, height);
        if (bOutput)
            ctx.putImageData(backdrop, rect[0], rect[1]);
        return;
    }

    if (bIsolated || !bGroup) {
    } else {
        //get backdrop first, but now we do noting; we will implement it in feauture;

        //if no backdrop, we show it directly.
         

    }


    return;
};



PDRenderStatus.prototype.ProcessSingleObjNoClip = function (obj, mtObj2Device, mode) {
    if (obj == undefined || obj == null) return;

    //   this.SetColorAndGraphState(obj.nClrStateID, obj.nGraphStateID);
    if (obj instanceof TextObj) {
        this.RenderText(obj, mtObj2Device, mode);
    }
    else if (obj instanceof ImgObj) {
        this.RenderImg(obj, mtObj2Device);
    }
    else if (obj instanceof PathObj) {
        this.RenderPath(obj, mtObj2Device);
    }
    else if (obj instanceof ShadingObj) {
        this.RenderShading(obj, mtObj2Device);
    } else if (obj instanceof InlineImgObj) {
        this.RenderImg(obj, mtObj2Device);
    } else if (obj instanceof FormObj) {
        this.RenderForm(obj, mtObj2Device, mode);
    }

   

};

PDRenderStatus.prototype.RenderForm = function (formObj, mtObj2Dev, mode) {

    //if (formObj.form.CountObj() < 1) return;
    //set the form's bbox as a clip
    //var rcDev = mtObj2Device.TransFormRect(obj.position[0], obj.position[1], obj.position[2], obj.position[3]);
    var clip = [[formObj.position[0], formObj.position[1], 6], [formObj.position[2], formObj.position[1], 2], [formObj.position[2], formObj.position[3], 2], [formObj.position[0], formObj.position[3], 2], [formObj.position[0], formObj.position[1], 2]];
    this.SetSingleClip(clip, mtObj2Dev);

    var status = new PDRenderStatus();
    //level, renderContext, cnvs, stopObj, transparency
    status.Init(this.m_Level + 1, this.m_renderContext, this.canvas, this.m_stopObj, this.m_Transparency);
    status.RenderObjList(formObj.form.GetPageObjects(), mtObj2Dev, mode);
};

PDRenderStatus.prototype.GetGraphStateByID = function (nID) {
    return this.m_curObjList.GetGraphStateByID(nID); ;
};

PDRenderStatus.prototype.SetColorAndGraphState = function (ctx, colorID, graphID) {
    if (0 == colorID || 0 == graphID) return;
    //set colors
    // var ctx = this.canvas.getContext("2d");// this.canvasBuf.getContext("2d");
    var clr = this.GetColors(colorID);
    ctx.strokeStyle = clr[0];
    ctx.fillStyle = clr[1];

    //set graph properties
    var graphState = this.GetGraphStateByID(graphID); //this.pdPage.GetGraphStateByID(graphID);
    if (null == graphState) return;
    //set dash
    var dashArray = [];
    for (var i = 0; i < graphState.nDashCount; i++) {
        dashArray[i] = Math.ceil(graphState.lsDash[i] / 72 * 96);
    }
    if (dashArray.length == 1)
        dashArray[1] = Math.ceil(graphState.lsDash[0] / 72 * 96);
    if (dashArray.length > 0) {
        if ('setLineDash' in ctx) {
            ctx.setLineDash(dashArray);
            ctx.lineDashOffset = Math.ceil(graphState.nDashPhase / 72 * 96);
        } else {
            ctx.mozDash = dashArray;
            ctx.mozDashOffset = Math.ceil(graphState.nDashPhase / 72 * 96);
        }
    }




    // line cap style
    switch (graphState.nCapStyle) {
        case 0: // Butt cap
            ctx.lineCap = "butt";
            break;
        case 1: // Round cap
            ctx.lineCap = "round";
            break;
        case 2: // Square cap
            ctx.lineCap = "square";
            break;
    }
    // line join style
    switch (graphState.joinStyle) {
        case 0: // Miter join
            ctx.lineJoin = "miter";
            break;
        case 1: // Round join
            ctx.lineJoin = "round";
            break;
        case 2: // Bevel join
            ctx.lineJoin = "bevel";
            break;
    }




    // line width
    ctx.lineWidth = graphState.fLineWidth < 1 ? 1 : graphState.fLineWidth; //Math.ceil(graphState.fLineWidth); // should consider matrix  pt-> px??
    var n = ctx.lineWidth;
    ctx.miterLimit = graphState.fJoinMiterLimit;
};
PDRenderStatus.prototype.GetClrStateByID = function (nID) {
    return this.m_curObjList.GetClrStateByID(nID);
};

PDRenderStatus.prototype.GetColors = function (colorID) {
    if (colorID <= 0) return ["RGB(255,255,255)","RGB(255,255,255)"];
    var colorState = this.GetClrStateByID(colorID); //this.pdPage.GetClrStateByID(colorID);
   
    var b = (colorState.strokeRGB >> 16) & 0xFF;
    var g = (colorState.strokeRGB >> 8) & 0xFF;
    var r = colorState.strokeRGB & 0xFF;
    var strokeRGB = "RGB(" + r + "," + g + "," + b + ")";
    var b = (colorState.fillRGB >> 16) & 0xFF;
    var g = (colorState.fillRGB >> 8) & 0xFF;
    var r = colorState.fillRGB & 0xFF;
    var fillRGB = "RGB(" + r + "," + g + "," + b + ")";
    var rst = [];
    rst[0] = strokeRGB;
    rst[1] = fillRGB;
    return rst;
};
PDRenderStatus.prototype.GetClipPathStateByID = function (nID) {
    return this.m_curObjList.GetClipPathStateByID(nID);
};
PDRenderStatus.prototype.GetGenStateByID = function (nID) {
    return this.m_curObjList.GetGenStateByID(nID);
};
PDRenderStatus.prototype.CreateTextClipLayer = function (clipPathState,mtObj2Dev) {
    if (clipPathState == undefined || clipPathState == null) return;
    var nText = clipPathState.CountTextClipObjs();
    if (nText <= 0) return;

    this.m_txtClipLayer = document.createElement("canvas"); //document.getElementById('myCanvas2'); //document.createElement("canvas");
    this.m_txtClipLayer.width = this.canvas.width;
    this.m_txtClipLayer.height = this.canvas.height;
    var maskCtx = this.m_txtClipLayer.getContext("2d");
    maskCtx.save();
    for (var n = 0; n < nText; n++) {
        var t = clipPathState.GetTextClipObjByIndex(n);
        if (t == undefined || t == null) continue;
        //     this.SetColorAndGraphState(maskCtx, t.nClrStateID, t.nGraphStateID);

        var b = (t.m_StrokeRGB >> 16) & 0xFF;
        var g = (t.m_StrokeRGB >> 8) & 0xFF;
        var r = t.m_StrokeRGB & 0xFF;
        var strokeRGB = "RGB(" + r + "," + g + "," + b + ")";
        var b = (t.m_FillRGB >> 16) & 0xFF;
        var g = (t.m_FillRGB >> 8) & 0xFF;
        var r = t.m_FillRGB & 0xFF;
        var fillRGB = "RGB(" + r + "," + g + "," + b + ")";
        maskCtx.strokeStyle = strokeRGB;
        maskCtx.fillStyle = fillRGB;


        var fillAlpha = t.m_fFillAlpha;
        var strokeAlpha = t.m_fStrokeAlpha;

        var mtFinal = PDMatrix.prototype.Concat2mt(t.matrix, mtObj2Dev);
        var mtTemp = new PDMatrix();
        if (t.m_fFontsize < 0)
            mtTemp.Set(-1, 0, 0, 1, 0, 0);
        else
            mtTemp.Set(1, 0, 0, -1, 0, 0);
        mtFinal = PDMatrix.prototype.Concat2mt(mtTemp, mtFinal);
       


        maskCtx.textAlign = "left";
        maskCtx.textBaseline = "alphabetic";

        var bFill = true;

        // 
        var content = t.GetContent();
        maskCtx.fillStyle = "black";
        if (bFill) {
            maskCtx.globalAlpha = fillAlpha;

            var fontInfo = this.m_curObjList.m_pdDoc.GetFontInfoByID(t.m_nFontID);
            var fontProperty = "";
            var fontsize = 1;
            fontsize = Math.abs(t.m_fFontsize);
            fontInfo.fontSize = fontsize;
            // font-family
            var family = fontInfo.fontFace;
            fontProperty += fontsize + "pt ";
            fontInfo.fontFamily = family;
            fontProperty += "'" + family + "'";

            maskCtx.font = fontProperty;// this.GetCSSFontInfo(textState, this.matrix, 1);
            var len = content.length;
            for (var i = 0; i < len; i++) {
                var curChar = content.charAt(i);
                var char_Matrix = new PDMatrix();
                char_Matrix.Set(1, 0, 0, 1, 0, 0);
                char_Matrix.e += i > 0 ? t.charPosArray[i] : 0;
                var mtToText = PDMatrix.prototype.Concat2mt(char_Matrix, t.matrix);

                var mtToDev = PDMatrix.prototype.Concat2mt(mtToText, mtObj2Dev);
                var mtTemp = new PDMatrix();
                mtTemp.Set(1, 0, 0, -1, 0, 0);
                var mtFinal2 = PDMatrix.prototype.Concat2mt(mtTemp, mtToDev);
                maskCtx.setTransform(mtFinal2.a, mtFinal2.b, mtFinal2.c, mtFinal2.d, mtFinal2.e, mtFinal.f);
                maskCtx.fillText(curChar, 0, 0);
            }


        }



    }
    maskCtx.restore();

};



//set a single clip, pathData:[[x,y,flag], [x,y,flag],...]
PDRenderStatus.prototype.SetSingleClip = function (pathData, mtObj2Device) {
    if (pathData == undefined || pathData == null || pathData.length == 0) return;

    var ctx = this.canvas.getContext("2d"); // this.canvasBuf.getContext("2d");
    ctx.setTransform(mtObj2Device.a, mtObj2Device.b, mtObj2Device.c, mtObj2Device.d, mtObj2Device.e, mtObj2Device.f);
    ctx.beginPath();
    this.DoPath(ctx, pathData);
    ctx.closePath();
    ctx.clip(); //clip it
};

PDRenderStatus.prototype.GetTextStateByID = function (nID) {
    return this.m_curObjList.GetTextStateByID(nID);
};

PDRenderStatus.prototype.RenderType3Text = function (textObj, mtObj2Device, mode) {
    var textState = this.GetTextStateByID(textObj.nTextStateID);
    var fontInfo = this.m_curObjList.m_pdDoc.GetFontInfoByID(textState.nFontID);
    if (fontInfo == undefined || fontInfo == null) return;
    if (fontInfo.fontType != 3) return;

    var type3Font = fontInfo.fontType3Info;
    var char_matrix = new PDMatrix();
    char_matrix.Set(type3Font.fontMatrix.a, type3Font.fontMatrix.b, type3Font.fontMatrix.c, type3Font.fontMatrix.d, type3Font.fontMatrix.e, type3Font.fontMatrix.f);
    char_matrix.Scale(textState.fontSize, textState.fontSize);

    var ctx = this.canvas.getContext("2d"); // this.canvasBuf.getContext("2d");

    ctx.save();
    this.SetColorAndGraphState(ctx, textObj.nClrStateID, textObj.nGraphStateID);

    var generalState = this.GetGenStateByID(textObj.nGenStateID);
    var fillAlpha = generalState.fillAlpha;
    var strokeAlpha = generalState.strokeAlpha;

    var nChar = textObj.content.length; //type3Font.lastChar - type3Font.firstChar + 1;
    for (var i = 0; i < nChar; i++) {
        var charcode = textObj.content.charCodeAt(i);
        if (charcode < type3Font.firstChar || charcode > type3Font.lastChar) continue;

        var index = charcode - type3Font.firstChar;
        // var charWidth = textObj.charPosArray[];
        var mtNewChar = new PDMatrix();
        mtNewChar.Set(char_matrix.a, char_matrix.b, char_matrix.c, char_matrix.d, char_matrix.e, char_matrix.f);
        //mtNewChar.e += i > 0 ? textObj.charPosArray[2 * i] : 0; //charWidth;
        //we just save width in json data.
        mtNewChar.e += i > 0 ? textObj.charPosArray[i] : 0;
        var mtToText = PDMatrix.prototype.Concat2mt(mtNewChar, textObj.matrix);
        var mtToDev = PDMatrix.prototype.Concat2mt(mtToText, mtObj2Device);
        //ctx.setTransform(mtToDev.a, mtToDev.b, mtToDev.c, mtToDev.d, mtToDev.e, mtToDev.f);

        //        for (var j = 0; j < type3Font.m_typeFlag.length; j++) {
        if (0 == type3Font.m_typeFlag[index]) {
            var glyphForm = type3Font.m_forms[index];
            if (glyphForm == undefined || null == glyphForm) continue;
            
            var status = new PDRenderStatus();
            //level, renderContext, cnvs, stopObj, transparency
            status.Init(this.m_Level+1, this.m_renderContext, this.canvas, this.m_stopObj, this.m_Transparency);
            status.RenderObjList(glyphForm.GetPageObjects(), mtToDev, mode);
        } else if (1 == type3Font.m_typeFlag[index]) {
            ctx.setTransform(mtToDev.a, mtToDev.b, mtToDev.c, mtToDev.d, mtToDev.e, mtToDev.f);
            var img = type3Font.m_imgs[index];
            ctx.drawImage(img, 0, 0);
        }

        //        }


    }
    ctx.restore();
};

//mode: 0 for normal, 1 for chrom
PDRenderStatus.prototype.RenderText = function (textObj, mtObj2Device, mode) {

    var textState = this.GetTextStateByID(textObj.nTextStateID);
    var fontInfo = this.m_curObjList.m_pdDoc.GetFontInfoByID(textState.nFontID);
    if (fontInfo == undefined || fontInfo == null) return;
    if (fontInfo.fontType == 3) {
        this.RenderType3Text(textObj, mtObj2Device, mode);
        return;
    }

    var ctx = this.canvas.getContext("2d"); // this.canvasBuf.getContext("2d");

    ctx.save();
    this.SetColorAndGraphState(ctx, textObj.nClrStateID, textObj.nGraphStateID);

    var generalState = this.GetGenStateByID(textObj.nGenStateID);
    var fillAlpha = generalState.fillAlpha;
    var strokeAlpha = generalState.strokeAlpha;

    var mtFinal = PDMatrix.prototype.Concat2mt(textObj.matrix, mtObj2Device);
    var mtTemp = new PDMatrix();
    if (textState.fontSize < 0)
        mtTemp.Set(-1, 0, 0, 1, 0, 0);
    else
        mtTemp.Set(1, 0, 0, -1, 0, 0);
    mtFinal = PDMatrix.prototype.Concat2mt(mtTemp, mtFinal);


    ctx.textAlign = "left";
    ctx.textBaseline = "alphabetic";
    var content = textObj.GetContent();

    var bStroke = false;
    var bFill = true;
    switch (textState.nTextMode) {
        case 0: // fill text
            bStroke = false;
            bFill = true;
            break;
        case 1: // stroke text
            bStroke = true;
            bFill = false;
            break;
        case 2: // fill, then stroke text
            bStroke = bFill = true;
            break;
        case 3: // neither fill nor stroke text (invisible)
        case 4: // fill text and add to for clipping (see above)
        case 5: // stroke text and add to path for clipping
        case 6: // fill, then stroke text and add to path for clipping
        case 7: // add text to path for clipping
            bStroke = bFill = false;
            break;
    }
    ctx.globalAlpha = fillAlpha;
    ctx.font = this.GetCSSFontInfo(textState, mtObj2Device, 1);
    
    var len = content.length;
    for (var i = 0; i < len; i++) {
        var curChar = content.charAt(i);
        var char_Matrix = new PDMatrix();
        char_Matrix.Set(1, 0, 0, 1, 0, 0);
        if (textObj.bVertWriting)
            char_Matrix.f += textObj.charPosArray[i];
        else
            char_Matrix.e += i > 0 ? textObj.charPosArray[i] : 0;
        //char_Matrix.f += i > 0 ? textObj.charPosArray[2 * i+1 ] : 0;
        var mtToText = PDMatrix.prototype.Concat2mt(char_Matrix, textObj.matrix);
        var mtToDev = PDMatrix.prototype.Concat2mt(mtToText, mtObj2Device);
        var mtFinal2 = PDMatrix.prototype.Concat2mt(mtTemp, mtToDev);
        ctx.setTransform(mtFinal2.a, mtFinal2.b, mtFinal2.c, mtFinal2.d, mtFinal2.e, mtFinal2.f);
        if (bFill)
            ctx.fillText(curChar, 0, 0);
        if (bStroke) {
            var graphState = this.GetGraphStateByID(textObj.nGraphStateID);
            ctx.lineWidth = graphState.fLineWidth / (Math.sqrt(mtFinal2.a * mtFinal2.a + mtFinal2.b * mtFinal2.b)); // should consider matrix  pt-> px??
            ctx.strokeText(curChar, 0, 0);
        }

    }
    ctx.restore();

};

PDRenderStatus.prototype.GetCSSFontInfo = function (txtState, mtObj2Dev, modeScale) {

    // set text state
    var fontInfo = this.m_curObjList.m_pdDoc.GetFontInfoByID(txtState.nFontID);
    var fontProperty = "";

    // font-size/line-height
    var fontsize = 1;
    fontsize = Math.abs(txtState.fontSize * this.viewScale) / Math.sqrt((mtObj2Dev.a * mtObj2Dev.a + mtObj2Dev.b * mtObj2Dev.b) / (modeScale * modeScale));
    //fontsize = Math.abs(txtState.fontSize) / (modeScale * modeScale);
   
    fontInfo.fontSize = fontsize;
    // font-family
    var family = fontInfo.fontFace;
    if(!fontInfo.m_bValide){
    	family = this.m_curObjList.m_pdDoc.GetLocalSubstFontFamily(fontInfo);
    }
    if (fontInfo.GetItalic())
        fontProperty += "italic" + " ";
    if (fontInfo.m_Weight == 700)
        fontProperty += 400 + " ";
    if(fontInfo.m_Weight == 900)
    	fontProperty += 700 + " ";
    fontProperty += fontsize + "pt ";
    fontInfo.fontFamily = family;
    return fontProperty += "'" + family + "'";
};



PDRenderStatus.prototype.RenderImg = function (imgObj, mtObj2Device) {
    if (imgObj == undefined || imgObj == null || imgObj.loadError == 1) return;
    var generalState = this.GetGenStateByID(imgObj.nGenStateID);
    var fillAlpha = generalState.fillAlpha;
    var mtFinal = PDMatrix.prototype.Concat2mt(imgObj.matrix, mtObj2Device);

    var ctx = this.canvas.getContext("2d"); // this.canvasBuf.getContext("2d");
    ctx.save();
    ctx.globalAlpha = fillAlpha;
    ctx.setTransform(mtFinal.a, mtFinal.b, -mtFinal.c, -mtFinal.d, mtFinal.e, mtFinal.f);
    ctx.translate(0, -1);
    ctx.drawImage(imgObj.domImg, 0, 0, 1, 1);
    ctx.restore();
};

PDRenderStatus.prototype.RenderPath = function (pathObj, mtObj2Device) {
    if (pathObj == undefined || pathObj == null) return;

    var ctx = this.canvas.getContext("2d"); // this.canvasBuf.getContext("2d");
    
    ctx.save();
    this.SetColorAndGraphState(ctx, pathObj.nClrStateID, pathObj.nGraphStateID);
    var generalState = this.GetGenStateByID(pathObj.nGenStateID);
    var fillAlpha = generalState.fillAlpha;
    var strokeAlpha = generalState.strokeAlpha;
    var rel = [1, true];

    var colorState = this.GetClrStateByID(pathObj.nClrStateID);
    //// first check whether pattern is used
    if ((colorState.strokeShadingPattern != null) || (colorState.fillShadingPattern != null) || (colorState.strokeTilingPattern != null) || (colorState.fillTilingPattern != null)) {
        var fillType = pathObj.fillType;
        var bStroke = pathObj.isStrokePath;

       rel = this.ProcessPathPattern(pathObj, mtObj2Device, fillType, bStroke);
        if (rel[0] == 0 && rel[1] == false) {
            ctx.restore();
            return; // all processed
        }
    }
    var temp = [];
    for (var i = 0, len = pathObj.CountPathPoints(); i < len; i++) {
        temp[i] = pathObj.GetPathPoint(i);
    }
    var mtFinal = PDMatrix.prototype.Concat2mt(pathObj.matrix, mtObj2Device);
    ctx.setTransform(mtFinal.a, mtFinal.b, mtFinal.c, mtFinal.d, mtFinal.e, mtFinal.f);
    ctx.beginPath();
    this.DoPath(ctx, temp);

    
    
    if (pathObj.isStrokePath && rel[1] == true) {// stroke or fill the path
        ctx.globalAlpha = strokeAlpha;
        ctx.stroke();
    }
    if (pathObj.fillType === 1 && rel[0] != 0) { // odd-even-fill // html5 canvas not support
        ctx.globalAlpha = fillAlpha;
        ctx.fill("evenodd");
    }
    else if (pathObj.fillType === 2 && rel[0] != 0) { // nonzero-fill
        ctx.globalAlpha = fillAlpha;
        ctx.fill("nonzero");
    }
    ctx.closePath(); //must put here, otherwise error occuc
    ctx.restore();
    
    
};

PDRenderStatus.prototype.ProcessPathPattern = function (pathObj, mtObj2Device, fillType, bStroke) {

    var shCnvs = document.createElement("canvas");
    shCnvs.width = this.canvas.width;
    shCnvs.height = this.canvas.height;
    var shCtx = shCnvs.getContext("2d");
    var dstCtx = this.canvas.getContext("2d");
    var dstImg = dstCtx.getImageData(0, 0, this.canvas.width, this.canvas.height);
    shCtx.putImageData(dstImg, 0, 0);

    this.SetColorAndGraphState(shCtx, pathObj.nClrStateID, pathObj.nGraphStateID);
    var generalState = this.GetGenStateByID(pathObj.nGenStateID);
    var fillAlpha = generalState.fillAlpha;
    var strokeAlpha = generalState.strokeAlpha;
    var type = fillType;
    var bS = bStroke;
    
    var colorState = this.GetClrStateByID(pathObj.nClrStateID);

    if (bStroke && ((colorState.strokeShadingPattern != null) || (colorState.strokeTilingPattern != null))) {
        if (this.DrawPathWithPattern(shCnvs, pathObj, mtObj2Device, 0, true)) {
            //copy data from shCnvs
            var rcDeviceDest = [];
            if (pathObj.position.length == 4){
                rcDeviceDest = mtObj2Device.TransFormRect(pathObj.position[0], pathObj.position[1], pathObj.position[2], pathObj.position[3]);
            }
            var shImg = shCtx.getImageData(rcDeviceDest[0], rcDeviceDest[1], rcDeviceDest[2] - rcDeviceDest[0], rcDeviceDest[3] - rcDeviceDest[1]);
            dstCtx.fillAlpha = fillAlpha;
	    var tmpCnvs = document.createElement("canvas");
		tmpCnvs.width = rcDeviceDest[2] - rcDeviceDest[0];
		tmpCnvs.height = rcDeviceDest[3] - rcDeviceDest[1];
		var tmpCtx = tmpCnvs.getContext("2d");
		tmpCtx.putImageData(shImg, 0, 0);
		dstCtx.setTransform(1,0,0,1,0,0);
		dstCtx.drawImage(tmpCnvs, rcDeviceDest[0], rcDeviceDest[1]);
         bS = false;
        }
        //bS = false;
    }

    if (fillType && ((colorState.fillShadingPattern != null) || (colorState.fillTilingPattern != null))) {
        type = 0;
        this.DrawPathWithPattern(this.canvas, pathObj, mtObj2Device, fillType, false);
    }

    return [type, bS];
};
//pathData:[[x,y, flag],[x,y,flag],...]
PDRenderStatus.prototype.PathIsRect = function (pathData) {
    var nPoint = pathData.length;
    if (nPoint != 5 && nPoint != 4) return false;

    if (nPoint == 5 && (pathData[0][0] != pathData[4][0] ||
			pathData[0][1] != pathData[4][1]) ||
			pathData[1][0] == pathData[3][0] && pathData[1][1] == pathData[3][1])
        return false;

    // All rectangle lines can only change one coord
    if (pathData[0][0] != pathData[3][0] && pathData[0][1] != pathData[3][1])
        return false;

    for (var i = 1; i < 4; i++) {
        if ((pathData[i][2] & 6) != 2) return false;
        if (pathData[i][0] != pathData[i - 1][0] && pathData[i][1] != pathData[i - 1][1])
            return false;
    }
    // If only 4 points, we need to make sure the last point is closed
    // TESTDOC: Bug #6843 - K1.pdf (editing)
    return nPoint == 5 || (pathData[3][2] & 1);
};

PDRenderStatus.prototype.DrawPathWithPattern = function (shCnvs, pathObj, mtObj2Device, fillType, bStroke) {
    if (pathObj == undefined || pathObj == null) return false;

    var generalState = this.GetGenStateByID(pathObj.nGenStateID);
    var fillAlpha = generalState.fillAlpha;
    var strokeAlpha = generalState.strokeAlpha;


    var pathData = [];
    var nlen = pathObj.CountPathPoints();
    for (var k = 0; k < nlen; k++) {
        pathData[k] = pathObj.GetPathPoint(k);
    }

    var shCtx = shCnvs.getContext("2d");

    //  var ctx = this.canvas.getContext("2d"); // this.canvasBuf.getContext("2d");
    var mtFinal = PDMatrix.prototype.Concat2mt(pathObj.matrix, mtObj2Device);
    if (pathObj.position.length < 4)
        pathObj.CalcBBox();
    var rcDeviceDest = [0, 0, shCnvs.width, shCnvs.height];

    rcDeviceDest = mtObj2Device.TransFormRect(pathObj.position[0], pathObj.position[1], pathObj.position[2], pathObj.position[3]);
    //ctx.setTransform(mtFinal.a, mtFinal.b, mtFinal.c, mtFinal.d, mtFinal.e, mtFinal.f);

    var colorState = this.GetClrStateByID(pathObj.nClrStateID);


    if (fillType) {
        //we should set path as clipping area;
        this.SetSingleClip(pathData, mtFinal);

        if (colorState.fillTilingPattern != undefined && colorState.fillTilingPattern != null) {//tilling patter
            //DrawTilingPattern
            this.DrawTillingPattern(shCnvs, colorState.fillTilingPattern, pathObj, mtObj2Device, rcDeviceDest, bStroke, fillAlpha, colorState.fillRGB);
            return true;
        } else if (colorState.fillShadingPattern != undefined && colorState.fillShadingPattern != null) {
            this.DrawShadingPattern(shCnvs, colorState.fillShadingPattern, mtObj2Device, rcDeviceDest, fillAlpha);
            return true;
        }
    }
    if (bStroke) {
        var bs = false;
        if (colorState.strokeTilingPattern != undefined && colorState.strokeTilingPattern != null) {//tilling patter
            //DrawTilingPattern
            this.DrawTillingPattern(shCnvs, colorState.strokeTilingPattern, pathObj, mtObj2Device, rcDeviceDest, bStroke, fillAlpha, colorState.fillRGB);
            bs = true;
        } else if (colorState.strokeShadingPattern != undefined && colorState.strokeShadingPattern != null) {
            this.DrawShadingPattern(shCnvs, colorState.strokeShadingPattern, mtObj2Device, rcDeviceDest, fillAlpha);
            bs = true;
        }

        if (1 == this.m_mode) {

            var tmpCnvs = this.domDoc.createElement("canvas"); //document.getElementById('myCanvas'); //
            tmpCnvs.width = shCnvs.width;
            tmpCnvs.height = shCnvs.height;

            var tmpCtx = tmpCnvs.getContext("2d");;
            this.SetColorAndGraphState(tmpCtx, pathObj.nClrStateID, pathObj.nGraphStateID);
            tmpCtx.save();
            //tmpCtx.globalCompositeOperation = "destination-in";
            tmpCtx.setTransform(mtFinal.a, mtFinal.b, mtFinal.c, mtFinal.d, mtFinal.e, mtFinal.f);

            var arrPath = [];
            var subPath = null;
            var len = pathData.length;
            for (var i = 0; i < len; i++) {
                var curPoint = pathData[i];
                var flag = curPoint[2];
                if (flag == 6) {
                    if (subPath == null) {
                        subPath = new Array();
                    } else {
                        arrPath.push(subPath);
                        subPath = null;
                        subPath = new Array();
                    }
                }
                subPath.push(curPoint);

                if (i == len - 1) {
                    arrPath.push(subPath);
                }
            }
            tmpCtx.beginPath();
            for (var j = 0; j < arrPath.length; j++) {
                var aPath = arrPath[j];

                // First a shortcut for rectangle filling
                // We take 4 or 5 points for a rectangle now, because some PDFs are too lazy to close the rectangle
                // TESTDOC: Bug #2316 - 5-1-1-1.pdf
                if (this.PathIsRect(aPath)) {
                    tmpCtx.rect(aPath[0][0], aPath[0][1], aPath[2][0] - aPath[0][0], aPath[2][1] - aPath[0][1]);
                    continue;
                } else {
                    this.DoPath(tmpCtx, aPath);
                }
            }
            tmpCtx.strokeStyle = "green";
            tmpCtx.stroke();
            tmpCtx.restore();

            var imgSh = shCtx.getImageData(rcDeviceDest[0], rcDeviceDest[1], rcDeviceDest[2], rcDeviceDest[3]);
            var imgPath = tmpCtx.getImageData(rcDeviceDest[0], rcDeviceDest[1], rcDeviceDest[2], rcDeviceDest[3]);
            for (var k = 0; k < imgPath.data.length; k += 4) {
                if (imgPath.data[k + 0] == 255 && imgPath.data[k + 1] == 255 && imgPath.data[k + 2] == 255)
                    continue;
                imgPath.data[k + 0] = imgSh.data[k];
                imgPath.data[k + 1] = imgSh.data[k + 1];
                imgPath.data[k + 2] = imgSh.data[k + 2];


            }
            
            shCtx.save();
            shCtx.setTransform(1, 0, 0, 1, 0, 0);
            shCtx.putImageData(imgPath, rcDeviceDest[0], rcDeviceDest[1]);
            shCtx.restore();
            return bs;
        }


        //now we stroke path and composite it with shading as before
        shCtx.save();
        shCtx.globalCompositeOperation = "destination-in";
        shCtx.setTransform(mtFinal.a, mtFinal.b, mtFinal.c, mtFinal.d, mtFinal.e, mtFinal.f);

        var arrPath = [];
        var subPath = null;
        var len = pathData.length;
        for (var i = 0; i < len; i++) {
            var curPoint = pathData[i];
            var flag = curPoint[2];
            if (flag == 6) {
                if (subPath == null) {
                    subPath = new Array();
                } else {
                    arrPath.push(subPath);
                    subPath = null;
                    subPath = new Array();
                }
            }
            subPath.push(curPoint);

            if (i == len - 1) {
                arrPath.push(subPath);
            }
        }
        shCtx.beginPath();
        for (var j = 0; j < arrPath.length; j++) {
            var aPath = arrPath[j];

            // First a shortcut for rectangle filling
            // We take 4 or 5 points for a rectangle now, because some PDFs are too lazy to close the rectangle
            // TESTDOC: Bug #2316 - 5-1-1-1.pdf
            if (this.PathIsRect(aPath)) {
                shCtx.rect(aPath[0][0], aPath[0][1], aPath[2][0] - aPath[0][0], aPath[2][1] - aPath[0][1]);
                continue;
            } else {
                this.DoPath(shCtx, aPath);
            }
        }
        shCtx.strokeStyle = "green"; 
        shCtx.stroke();
        shCtx.restore();

        return bs;
        // return false;
    }
    return false;
};

PDRenderStatus.prototype.DrawShadingPattern = function (shCnvs, shPattern, mtObj2Device, rcDeviceDest, fillAlpha) {
    var mtFinal = PDMatrix.prototype.Concat2mt(shPattern.m_mtPattern2Form, mtObj2Device);
    PDRenderStatus.prototype.NormalizeRect(rcDeviceDest);
    _DrawShadingPattern(shPattern, mtFinal, rcDeviceDest, fillAlpha, shCnvs);
};

PDRenderStatus.prototype.DrawTillingPattern = function (tCnvs, tP, pathObj, mtObj2Device, rcDeviceDest, bStroke, fillAlpha, fillArgb) {
    PDRenderStatus.prototype.NormalizeRect(rcDeviceDest);
    _DrawTillingPattern(tCnvs, this.pdPage, tP, pathObj, mtObj2Device, rcDeviceDest, bStroke, fillAlpha, fillArgb);

};
//pathData:in format [[x,y,flag], ...]
PDRenderStatus.prototype.DoPath = function (ctx, pathData) {

    var len = pathData.length;
    var bezierbeginIndex = -1, bezierendIndex = -1;

    //  ctx.beginPath();

    for (var i = 0; i < len; i++) {
        var curPoint = pathData[i];
        var flag = curPoint[2];
        switch (flag) {
            case 1:
                ctx.lineTo(pathData[0][0], pathData[0][1]);
                break;
            case 2:
            case 3:
                ctx.lineTo(curPoint[0], curPoint[1]);
                break;
            case 4:
            case 5:
                {
                    if (bezierbeginIndex === -1) {
                        bezierbeginIndex = i;
                    }
                    bezierendIndex = i;
                    if (i + 1 < len) {
                        if ((bezierendIndex - bezierbeginIndex + 1) % 3 === 0) {// outline the bezier curve
                            ctx.bezierCurveTo(pathData[bezierbeginIndex][0], pathData[bezierbeginIndex][1],
										pathData[bezierbeginIndex + 1][0], pathData[bezierbeginIndex + 1][1],
										pathData[bezierbeginIndex + 2][0], pathData[bezierbeginIndex + 2][1]);
                            bezierbeginIndex = -1;
                            bezierendIndex = -1;
                        }
                    }
                    else { // end the figure	// outline the bezier curve
                        var bezierPtCount = bezierendIndex - bezierbeginIndex + 1;
                        if (bezierPtCount % 3 === 0) {
                            ctx.bezierCurveTo(pathData[bezierbeginIndex][0], pathData[bezierbeginIndex][1],
										pathData[bezierbeginIndex + 1][0], pathData[bezierbeginIndex + 1][1],
										pathData[bezierbeginIndex + 2][0], pathData[bezierbeginIndex + 2][1]);
                            bezierbeginIndex = -1;
                            bezierendIndex = -1;
                        }
                    }
                }
                break;
            case 6:
                ctx.moveTo(curPoint[0], curPoint[1]);
                break;
            default:
                break;
        }
    }
    //  ctx.closePath();//if close path, canvase will close path automatickly, so it is wrong;
};

PDRenderStatus.prototype.RenderShading = function (shadingObj, mtObj2Device) {
    var ctx = this.canvas.getContext("2d"); // this.canvasBuf.getContext("2d");

    var mtFinal = PDMatrix.prototype.Concat2mt(shadingObj.matrix, mtObj2Device);
    //    ctx.setTransform(mtFinal.a, mtFinal.b, mtFinal.c, mtFinal.d, mtFinal.e, mtFinal.f);
    var rcBBox = shadingObj.GetBBox(mtObj2Device); //mtObj2Device.TransFormRect(shadingObj.BBox[0], shadingObj.BBox[1], shadingObj.BBox[2], shadingObj.BBox[3]);
    //first we should set bbox as clipping area;
 /*   
    ctx.beginPath();
    ctx.rect(rcBBox[0], rcBBox[1], rcBBox[2] - rcBBox[0], rcBBox[3] - rcBBox[1]);
    ctx.closePath();
    ctx.clip();
  */  

    ctx.save();
    this.SetColorAndGraphState(ctx, shadingObj.nClrStateID, shadingObj.nGraphStateID);
    var generalState = this.GetGenStateByID(shadingObj.nGenStateID);
    var fillAlpha = generalState.fillAlpha;
    var strokeAlpha = generalState.strokeAlpha;

    PDRenderStatus.prototype.NormalizeRect(rcBBox);
    _DrawShadingPattern(shadingObj.shadingpattern, mtFinal, rcBBox, fillAlpha, this.canvas);
    
    ctx.restore();
};

function _CurRenderFormInfo() {
    this.formObj = null;
    this.m_Objs = null;//PDPageObjects instance;
    this.m_TrailObj = null;
    this.m_UsedAlphaRects = [];//rect list([[left, top, right, bottom], [],...]) where the alpha value of pixel is useful 

    this.RectIsUsedAlpha = function (rc) {
        for(var i=0; i<this.m_UsedAlphaRects.length; i++)
        {
            var rect = this.m_UsedAlphaRects[i];
            if(rect[0] >= rc[0] && rect[1] >= rc[1] && rect[2] >= rc[2] && rect[3] >= rc[3])
            return true;
        }
         return false;
    };
};

function gGetFormTrailObj(formObj) {
    var os = formObj.form.GetPageObjects();
    if (null == os) return null;

    var n = os.objectArr.length;
    var trail = null;
    for (var i = 0; i < n; i++) {
        var t = os.objectArr[i];
        if (null != t) {
            trail = t;
        }

    }
    if (trail instanceof FormObj) {
        return gGetFormTrailObj(trail);
    }
    return trail;

};
function _Render_Item(objs, mtObj2Dev)
{
	this.m_objList = objs;
	this.m_mtObj2Dev = mtObj2Dev;
};

function PDRenderContext(){
	this.domDoc = null;
    this.canvas = null;
    this.m_arrRenderItemList = [];//_Render_Item object
    this.m_mode = 0; //0:IE, 1 : web-kit, 2:firefox,
    this.globalUseAlphaWhenBitblt = true;
    this.bgClr = "RGBA(255, 255, 255, 255)";
    this.m_curRenderFormRecord = null; //_CurRenderFormInfo
    this.m_bitmap = null; //the fulling image data of rendering canvas

    this.SaveBackground = function () {
        this.m_bitmap = this.canvas.getContext("2d").getImageData(0, 0, this.canvas.width, this.canvas.height);
    };
    this.FreeBackground = function () {
        delete this.m_bitmap;
        this.m_bitmap = null;
    };
    this.SetCurRenderFormRecord = function (formObj) {
        var info = new _CurRenderFormInfo();
        info.formObj = formObj;
        info.m_Objs = formObj.form.GetPageObjects();
        info.m_TrailObj = gGetFormTrailObj(formObj);
        this.m_curRenderFormRecord = info;
    };
    this.BelongToCurRenderingForm = function (obj) {

        if (null == this.m_curRenderFormRecord) return false;
        for (var i = 0, objCount = this.m_curRenderFormRecord.m_Objs.objectArr.length; i < objCount; i++) {
            var o = this.m_curRenderFormRecord.m_Objs.objectArr[i];
            if (obj == o) return true;
            if (o instanceof PDForm) {
                var r = new PDRenderContext();
                var c = new _CurRenderFormInfo();
                c.m_Objs = o.GetPageObjects();
                r.m_curRenderFormRecord = c;

                var rel = r.BelongToCurRenderingForm(obj);
                if (rel) return true;
            }


        }
        return false;
    };

    this.AppandObjList = function(objList, mtObj2Dev)
    {
    	var item = new _Render_Item(objList, mtObj2Dev);
    	this.m_arrRenderItemList.push(item);
    };
    this.ClearRect = function (cnvs, left, top, width, height, backgroundClr) {
        var ctx = cnvs.getContext("2d");
        ctx.fillStyle = backgroundClr;
        ctx.fillRect(left, top, width, height);
        //ctx.clearRect(left, top, width, height);
    };
    this.Render = function (cnvs, stopObj, mtLast, viewScale, mode) {
        this.ClearRect(cnvs, 0, 0, cnvs.width, cnvs.height, this.bgClr);
        this.m_mode = mode;
        this.canvas = cnvs;
        var nItem = this.m_arrRenderItemList.length;
        for (var i = 0; i < nItem; i++) {
            var item = this.m_arrRenderItemList[i];
            if (null == item) continue;

            if (null != mtLast) {
                var mtFinal = new PDMatrix();
                mtFinal.Clon(item.m_mtObj2Dev);
                mtFinal.Concat(mtLast.a, mtLast.b, mtLast.c, mtLast.d, mtLast.e, mtLast.f, false);

                var status = new PDRenderStatus();
                //level, renderContext, cnvs, stopObj, transparency
                status.Init(0, this, cnvs, stopObj, viewScale, item.m_objList.m_Transparency);
                //objs, mtObj2Device, mode
                status.RenderObjList(item.m_objList, mtFinal, mode);
            }
            else {
                var status = new PDRenderStatus();
                //level, renderContext, cnvs, stopObj, transparency
                status.Init(0, this, cnvs, stopObj, viewScale, item.m_objList.m_Transparency);
                //objs, mtObj2Device, mode
                status.RenderObjList(item.m_objList, item.m_mtObj2Dev, mode);
            }


        }
    };
    
    this.DrawObjList = function(cnvs, objList, obj2Dev)
    {
    	this.AppandObjList(objList, obj2Dev);
    	this.Render(cvns, null,null, this.m_mode);
    };
};




